find和xargs连用虽好,但用起来要小心哦~
上一篇公众号文章,前面讲了很多故事和八卦,但通篇最重要的一点就是用rm -fr softlink和rm -fr softlink/根本就是两个效果完全不同的命令,希望能给自动补全党带来一点点启示意义。今天的一条导致危险的命令也和rm -fr有关,但是主角不是它,是xargs。
find . -name "*.fasta" | xargs wc -l
比如我们在linux shell tricks for bioinformatics I里面提到的一条指令,这行命令可以统计当前文件夹下,所有的fasta文件的行数。xargs在里面的意义就是将fasta文件的名字,一个一个地传递给wc -l命令。
那我们再看看下面的一条命令:
不安全命令,非错误命令:
find . -maxdepth 1 -name "*.txt" | xargs rm -fr
这个命令也许会达到你的目的。但是,一次能够正确执行你想要的操作,并不代表这个命令每次都能如你所愿。并且事实上,这条命令是非常危险的!
小伙伴请想象一下这个场景: 你辛辛苦苦做了三年生信,好容易攒了很多代码和Pipeline。把这些东西放在你的干活的电脑的Code和Pipeline的文件夹。你师兄毕业了,好心的他决定把他的代码给你,他拷给你好多文件夹,叫Zhaocheng Code,Zhaocheng Pipeline, Zhaocheng BlaBla等等。因为个人喜好缘故,他喜欢用空格来分隔文件名里的字符串。然后你点进去一看,全部是perl(破)代码。作为python爱好者的你,决定将它弃之如敝履。
来,跟着我的操作做一个测试。
find ./ -maxdepth 1 -name "*Zhaocheng*" | xargs rm -fr
运行完这句shell命令之后,你发现你想删掉的zhaocheng Code,zhaocheng Pipeline, zhaocheng BlaBla文件夹还在,你自己积攒的Code, Pipeline反而被删了! 此刻你的内心,想必一定是一万头神兽飘过。稍微平静一点之后呢,我们来试图理解一下其中的原因。
前面的都是些不痛不痒的,下面的几句话希望大家能够牢记。
1. xargs的默认定界符是空格。
2. 空字符(Null character)又称结束符,缩写NUL,是一个数值为0的控制字符。编程语言会自动在字符串结尾加上结束符,不需由程序员自己打上去。当你find到了Zhaocheng Code之后,通过xargs传递给rm -fr时,因为xargs的默认定界符是空格。xargs会将Zhaocheng Code拆分成rm -fr Zhaocheng和rm -fr Code。然后这就是为什么你想删掉的没有删掉,而不想删的却误删了的原因。这种情况不一定每次都能碰到,但是有一种情况风险是非常高的。就是删除文献的时候,你想一下,文献的题目都是空格分开的,如果某一个字段正好跟你的文件夹重名,那就真的哔了狗了。
那这么说来,这个命令是不是不能用了啊。
其实还是能够用的。只需要指定定界符,将定界符制定为字符串的结束符null字符串就行。这样可以在xargs命令中,以null字符串(\0),也就是结束符来分隔输入参数,但find找到了Zhaocheng Code这个文件夹之后,是将这个名称整体地传递给rm -fr Zhaocheng Code来执行,这样就规避了空格作为定界符带来的风险。命令如下:
find ./ -maxdepth 1 -name "*Zhaocheng*" -print0 | xargs -0 rm -fr
也有其它的方法:
find ./ -maxdepth 1 -name "*Zhaocheng*" | xargs -I {} rm -fr {}
或者
find . -maxdepth 1 -name "*Zhaocheng*" -exec rm -fr {} \;
这样就能规避风险,当然方法还有很多很多,比如说,先将文件或者文件名里的空格全部替换为下划线,然后再执行操作。虽然这方法笨了点,但是非常稳妥。
最后还有一个建议,就是文件夹或者文件名里不要人为地加入空格,强迫症患者看着难受,空格全部用下划线代替。
PS: 二月已经跑步120公里,加油,奔跑的天地本无心!